package clazz.reflection;

import entity.People;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.stream.Stream;

/**
 * @author lidong
 */
public class ReflectionClass {

    private static final Logger logger = LoggerFactory.getLogger(ReflectionClass.class);

    /**
     * newInstance()：弱类型，只能调用无参的构造函数
     * new()：强类型，能调用任何的Public构造方法
     */

    public void show() {
        logger.info("当前的类是ReflectionClass");
    }


    /**
     * Class.forName()要求Jvm查找并且加载指定的类
     */
    @Test
    public void t1() {
        try {
            // 使用Class类的forName静态方法获得类的对象
            Class clazz = Class.forName("clazz.reflection.ReflectionClass");
            Method[] declaredMethods = clazz.getDeclaredMethods();
            for (Method x : declaredMethods) {
                logger.info(String.valueOf(x));
            }
            // newInstance()和 new 有相同的功能，但是newInstance实现动态加载类，newInstance通过调用无参的构造方法
            // newInstance()分解为两个步骤，先加载某个类，然后进行实例化。
            ReflectionClass reflectionClass = (ReflectionClass) clazz.newInstance();
            reflectionClass.show();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        }
    }

    @Test
    public void t2() {
        ReflectionClass reflectionClass = new ReflectionClass();
        // getClass方法获得这个类的对象
        Class<? extends ReflectionClass> aClass = reflectionClass.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        Stream.of(declaredMethods).forEach(System.out::println);
    }


    @Test
    public void t3() {
        // 直接使用.class方法，他会自动去匹配
        Class clazz = ReflectionClass.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        Stream.of(declaredMethods).forEach(System.out::println);
    }


    /**
     * 通过反射拿到对象的属性和值
     */
    @Test
    public void t4() throws IllegalAccessException {
        People people = new People(1, "张三", 24);
        // 得到类对象
        Class clazz = people.getClass();
        Field[] fs = clazz.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            // 设置些属性是可以访问的
            f.setAccessible(true);
            // 得到此属性的值
            Object val = f.get(people);
            logger.info("name:" + f.getName() + " value = " + val);
            // 得到此属性的类型
            String type = f.getType().toString();
            String name = f.getName();
            if ("name".equals(name)) {
                f.set(people, "李四");
            }
        }
        logger.info(people.toString());
    }


}
